package com.ruoyi.common.utils.ps2;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class ImageDownloaderWithReportOnly {

    // 配置参数
    private static final long MAX_FILE_SIZE = 8 * 1024 * 1024; // 最大允许的文件大小 (8MB)
    private static final float DEFAULT_QUALITY = 0.92f;        // 默认压缩质量
    private static final float MIN_QUALITY = 0.7f;             // 最低压缩质量
    private static final int MIN_WIDTH = 800;                  // 最小宽度限制
    private static final int MIN_HEIGHT = 600;                 // 最小高度限制
    private static final int BATCH_SIZE = 10000;               // 每个文件夹的图片数量
    private static final String BASE_DIR = "E:/stock_photos";  // 基础下载目录
    private static final String CSV_FILE = "C:\\Users\\lenovo\\Desktop\\photo_origin_url_list_20250805.csv"; // CSV文件路径
    private static final String REPORT_FILE = "download_report.csv"; // 报告文件路径
    private static final int MAX_RETRIES = 3;                  // 最大重试次数
    private static final int RETRY_DELAY = 2000;               // 重试延迟(毫秒)
    private static final String ERROR_LOG_FILE = "error_log.txt"; // 错误日志文件

    public static void main(String[] args) {
        try {
            // 1. 创建基础目录
            Path basePath = Paths.get(BASE_DIR);
            createDirIfNotExists(basePath);

            // 2. 初始化报告文件和错误日志
            Path reportPath = Paths.get(BASE_DIR, REPORT_FILE);
            Path errorLogPath = Paths.get(BASE_DIR, ERROR_LOG_FILE);
            initReportFile(reportPath);
            initErrorLogFile(errorLogPath);

            // 3. 加载已处理的stock_no记录
            Set<String> processedStockNos = loadProcessedStockNos(reportPath);
            System.out.println("已处理记录数: " + processedStockNos.size());

            // 4. 加载CSV数据
            List<ImageRecord> records = loadCsvData(Paths.get(CSV_FILE));
            List<ImageRecord> pendingRecords = filterPendingRecords(records, processedStockNos);
            System.out.printf("总记录数: %d, 待下载数: %d%n",
                    records.size(), pendingRecords.size());

            // 5. 下载图片并记录到报告文件
            downloadAndRecord(pendingRecords, reportPath, errorLogPath);

            System.out.println("处理完成!");
        } catch (Exception e) {
            System.err.println("程序执行出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 初始化错误日志文件
     */
    private static void initErrorLogFile(Path errorLogPath) throws IOException {
        if (!Files.exists(errorLogPath)) {
            Files.createFile(errorLogPath);
            System.out.println("已创建错误日志文件: " + errorLogPath);
        }
    }

    /**
     * 初始化报告文件（写入标题行）
     */
    private static void initReportFile(Path reportPath) throws IOException {
        if (!Files.exists(reportPath)) {
            try (BufferedWriter writer = Files.newBufferedWriter(reportPath, StandardCharsets.UTF_8)) {
                // 添加状态和错误信息列
                writer.write("stock_no,original_filename,new_filename,status,error_message");
                writer.newLine();
            }
            System.out.println("已初始化报告文件: " + reportPath);
        }
    }

    /**
     * 加载已处理的stock_no
     */
    private static Set<String> loadProcessedStockNos(Path reportPath) throws IOException {
        Set<String> processed = new HashSet<>();
        if (!Files.exists(reportPath)) {
            return processed;
        }

        try (BufferedReader reader = Files.newBufferedReader(reportPath, StandardCharsets.UTF_8)) {
            // 跳过标题行
            String line = reader.readLine();
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",", 5);
                if (parts.length >= 1) {
                    processed.add(parts[0].trim());
                }
            }
        }
        return processed;
    }

    /**
     * 从CSV文件加载数据
     */
    private static List<ImageRecord> loadCsvData(Path csvPath) throws IOException {
        List<ImageRecord> records = new ArrayList<>();

        try (BufferedReader br = Files.newBufferedReader(csvPath, StandardCharsets.UTF_8)) {
            String line;
            boolean isFirstLine = true;

            while ((line = br.readLine()) != null) {
                // 跳过标题行
                if (isFirstLine) {
                    isFirstLine = false;
                    continue;
                }

                // 解析CSV行
                String[] parts = line.split(",", 2);
                if (parts.length < 2) {
                    System.err.println("跳过无效行: " + line);
                    continue;
                }

                // 创建记录对象
                ImageRecord record = new ImageRecord();
                record.stockNo = parts[0].trim();
                record.downloadUrl = parts[1].trim();

                records.add(record);
            }
        }
        return records;
    }

    /**
     * 过滤出未处理的记录
     */
    private static List<ImageRecord> filterPendingRecords(List<ImageRecord> records, Set<String> processedStockNos) {
        List<ImageRecord> pending = new ArrayList<>();
        for (ImageRecord record : records) {
            if (!processedStockNos.contains(record.stockNo)) {
                pending.add(record);
            }
        }
        return pending;
    }

    /**
     * 下载图片并记录到报告文件
     */
    private static void downloadAndRecord(List<ImageRecord> records, Path reportPath, Path errorLogPath) {
        AtomicInteger successCount = new AtomicInteger(47166);
        AtomicInteger failureCount = new AtomicInteger(0);
        int batchIndex = 0;

        try (BufferedWriter reportWriter = Files.newBufferedWriter(reportPath,
                StandardCharsets.UTF_8,
                StandardOpenOption.APPEND,
                StandardOpenOption.CREATE);
             BufferedWriter errorWriter = Files.newBufferedWriter(errorLogPath,
                     StandardCharsets.UTF_8,
                     StandardOpenOption.APPEND,
                     StandardOpenOption.CREATE)) {

            // 处理每条记录
            for (ImageRecord record : records) {
                String status = "failure";
                String errorMessage = "";
                String originalFilename = extractFilenameFromUrl(record.downloadUrl);
                String newFilename = "";

                try {
                    // 计算批次文件夹
                    int currentSuccess = successCount.get();
                    batchIndex = (currentSuccess / BATCH_SIZE) + 1;
                    Path batchDir = Paths.get(BASE_DIR, "batch_" + batchIndex);
                    createDirIfNotExists(batchDir);

                    // 生成文件名
                    int fileNumber = currentSuccess + 1;
                    String fileName = String.format("原图_%08d.jpg", fileNumber);
                    Path outputPath = batchDir.resolve(fileName);

                    // 下载图片（带重试机制）
                    boolean success = false;
                    Exception lastError = null;
                    for (int i = 0; i < MAX_RETRIES; i++) {
                        try {
                            if (downloadAndProcessImage(record.downloadUrl, outputPath)) {
                                success = true;
                                break;
                            }
                        } catch (Exception e) {
                            lastError = e;
                            System.err.printf("下载尝试 %d/%d 失败 [%s]: %s%n",
                                    i+1, MAX_RETRIES, record.downloadUrl, e.getMessage());
                            if (i < MAX_RETRIES - 1) {
                                Thread.sleep(RETRY_DELAY);
                            }
                        }
                    }

                    if (success) {
                        // 更新计数器
                        successCount.incrementAndGet();
                        status = "success";
                        newFilename = "batch_" + batchIndex + "/" + fileName;

                        // 每10张打印进度
                        if (successCount.get() % 10 == 0) {
                            System.out.printf("已下载: %d 张, 当前批次: %d, 文件名: %s%n",
                                    successCount.get(), batchIndex, fileName);
                        }
                    } else {
                        errorMessage = (lastError != null) ? lastError.getMessage() : "未知错误";
                        failureCount.incrementAndGet();
                        System.err.printf("下载失败 [%s]: %s%n", record.downloadUrl, errorMessage);

                        // 写入错误日志
                        errorWriter.write(String.format("[%s] %s | 错误: %s%n",
                                new Date(), record.downloadUrl, errorMessage));
                        errorWriter.flush();
                    }
                } catch (Exception e) {
                    errorMessage = e.getMessage();
                    failureCount.incrementAndGet();
                    System.err.printf("处理图片失败 [%s]: %s%n", record.downloadUrl, errorMessage);

                    // 写入错误日志
                    errorWriter.write(String.format("[%s] %s | 错误: %s%n",
                            new Date(), record.downloadUrl, errorMessage));
                    errorWriter.flush();
                } finally {
                    // 无论成功失败，都写入报告
                    try {
                        reportWriter.write(String.format("%s,%s,%s,%s,\"%s\"",
                                record.stockNo,
                                originalFilename,
                                newFilename,
                                status,
                                errorMessage.replace("\"", "\"\""))); // 转义双引号
                        reportWriter.newLine();
                        reportWriter.flush(); // 确保立即写入磁盘
                    } catch (IOException e) {
                        System.err.println("写入报告失败: " + e.getMessage());
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("文件处理失败: " + e.getMessage());
        }

        System.out.printf("下载完成! 成功: %d 张, 失败: %d 张%n",
                successCount.get(), failureCount.get());
    }

    /**
     * 从URL中提取原始文件名
     */
    private static String extractFilenameFromUrl(String url) {
        try {
            // 移除URL参数
            int paramIndex = url.indexOf('?');
            String cleanUrl = (paramIndex > 0) ? url.substring(0, paramIndex) : url;

            // 从路径中获取文件名
            int lastSlash = cleanUrl.lastIndexOf('/');
            if (lastSlash != -1 && lastSlash < cleanUrl.length() - 1) {
                return cleanUrl.substring(lastSlash + 1);
            }
        } catch (Exception e) {
            System.err.println("无法从URL提取文件名: " + url);
        }
        // 如果无法提取，使用默认文件名
        return "unknown.jpg";
    }

    /**
     * 创建目录（如果不存在）
     */
    private static void createDirIfNotExists(Path dir) throws IOException {
        if (!Files.exists(dir)) {
            Files.createDirectories(dir);
            System.out.println("创建目录: " + dir);
        }
    }

    /**
     * 下载并处理图片
     */
    private static boolean downloadAndProcessImage(String imageUrl, Path outputPath) {
        try {
            // 创建临时文件
            Path tempFile = Files.createTempFile("download-", ".tmp");

            try {
                // 下载原始图片到临时文件
                if (!downloadOriginalImage(imageUrl, tempFile)) {
                    return false;
                }

                // 检查文件大小并决定是否需要压缩
                long fileSize = Files.size(tempFile);
                if (fileSize <= MAX_FILE_SIZE) {
                    // 文件小于8MB，直接移动到目标位置
                    Files.move(tempFile, outputPath, StandardCopyOption.REPLACE_EXISTING);
                    return true;
                } else {
                    // 文件大于8MB，进行压缩处理
                    return compressAndScaleImage(tempFile, outputPath);
                }
            } finally {
                // 确保删除临时文件
                Files.deleteIfExists(tempFile);
            }
        } catch (IOException e) {
            System.err.printf("图片处理失败 [%s]: %s%n", imageUrl, e.getMessage());
            return false;
        }
    }

    /**
     * 下载原始图片到临时文件
     */
    private static boolean downloadOriginalImage(String imageUrl, Path tempFile) {
        try {
            URL url = new URL(imageUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(10000); // 10秒连接超时
            conn.setReadTimeout(60000);    // 60秒读取超时

            // 检查HTTP响应码
            if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                System.err.printf("下载失败 [%s]: HTTP错误 %d%n", imageUrl, conn.getResponseCode());
                return false;
            }

            // 下载图片到临时文件
            try (InputStream in = conn.getInputStream()) {
                Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING);
            }
            return true;
        } catch (Exception e) {
            System.err.printf("下载失败 [%s]: %s%n", imageUrl, e.getMessage());
            return false;
        }
    }

    /**
     * 压缩并缩放图片到目标路径
     */
    private static boolean compressAndScaleImage(Path sourceFile, Path targetPath) {
        try (InputStream input = Files.newInputStream(sourceFile)) {
            // 读取原始图片
            BufferedImage originalImage = ImageIO.read(input);
            if (originalImage == null) {
                System.err.println("无法读取图片: " + sourceFile);
                return false;
            }

            // 获取原始尺寸
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();
            double aspectRatio = (double) originalWidth / originalHeight;

            // 计算初始缩放目标尺寸（保持原始宽高比）
            int targetWidth = Math.max(originalWidth, MIN_WIDTH);
            int targetHeight = (int) Math.round(targetWidth / aspectRatio);

            // 如果高度低于最小值，重新计算宽度
            if (targetHeight < MIN_HEIGHT) {
                targetHeight = MIN_HEIGHT;
                targetWidth = (int) Math.round(targetHeight * aspectRatio);
            }

            // 逐步优化尺寸和压缩质量
            float quality = DEFAULT_QUALITY;
            BufferedImage scaledImage = null;

            for (int attempt = 1; attempt <= 5; attempt++) {
                // 如果需要缩放，创建缩放后的图片
                if (originalWidth > targetWidth || originalHeight > targetHeight) {
                    scaledImage = scaleImage(originalImage, targetWidth, targetHeight);
                } else {
                    scaledImage = originalImage;
                }

                // 尝试保存压缩后的图片
                if (compressImage(scaledImage, targetPath, quality)) {
                    long compressedSize = Files.size(targetPath);
                    if (compressedSize <= MAX_FILE_SIZE) {
                        return true;
                    }

                    // 删除过大的文件
                    Files.deleteIfExists(targetPath);
                }

                // 调整参数进行下一次尝试
                if (quality > MIN_QUALITY) {
                    // 首先降低质量
                    quality = Math.max(MIN_QUALITY, quality - 0.1f);
                } else {
                    // 质量已到最低，开始缩小尺寸比例
                    targetWidth = (int) (targetWidth * 0.9);
                    targetHeight = (int) Math.round(targetWidth / aspectRatio);

                    // 确保不小于最小尺寸
                    if (targetWidth < MIN_WIDTH || targetHeight < MIN_HEIGHT) {
                        System.err.println("无法压缩到8MB以内，已达到最小尺寸限制");
                        return false;
                    }
                }
            }

            System.err.println("经过5次尝试仍无法压缩到8MB以内");
            return false;
        } catch (IOException e) {
            System.err.println("图片压缩失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 压缩图片到目标路径
     */
    private static boolean compressImage(BufferedImage image, Path targetPath, float quality) {
        try (OutputStream output = Files.newOutputStream(targetPath)) {
            // 获取JPEG图片写入器
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
            if (!writers.hasNext()) {
                System.err.println("找不到JPEG编码器");
                return false;
            }

            ImageWriter writer = writers.next();
            ImageWriteParam param = writer.getDefaultWriteParam();

            // 启用压缩并设置压缩质量
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(quality);

            // 设置压缩参数
            param.setProgressiveMode(ImageWriteParam.MODE_DEFAULT);

            try (ImageOutputStream ios = ImageIO.createImageOutputStream(output)) {
                writer.setOutput(ios);
                writer.write(null, new IIOImage(image, null, null), param);
            } finally {
                writer.dispose();
            }

            return true;
        } catch (IOException e) {
            System.err.println("图片压缩失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 按比例缩放图片
     */
    private static BufferedImage scaleImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
        // 创建高质量缩放图像
        BufferedImage scaledImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = scaledImage.createGraphics();

        // 设置高质量渲染参数
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制缩放后的图像
        g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
        g2d.dispose();

        return scaledImage;
    }

    /**
     * 图片记录类
     */
    static class ImageRecord {
        String stockNo;
        String downloadUrl;
    }
}